library ieee;
use ieee.std_logic_1164.all;

entity MIPS is
    port(
    rst, clk, dump: in std_logic;
    instr, pc: out std_logic_vector(31 downto 0)
    );
end MIPS;

architecture behav of MIPS is
    component fetch
        port(
        Jump, PcSrcM, clk, rst:
            in std_logic;
        PcBranchM:
            in std_logic_vector(31 downto 0);
        InstrF, PCF, PCPlus4F:
            out std_logic_vector(31 downto 0)
        );
    end component;

    component decode
        port(
        RegWrite, clk:
            in std_logic;
        A3:
            in std_logic_vector(4 downto 0);
        InstrD, Wd3, PCPlus4InD:
            in std_logic_vector(31 downto 0);

        RtD, RdD:
            out std_logic_vector(4 downto 0);
        SigImmD, RD1D, RD2D, PCPlus4OutD:
            out std_logic_vector(31 downto 0);
        MemToRegD, MemWriteD, BranchD, AluSrcD, RegDstD, RegWriteD, JumpD:
            out std_logic;
        AluControlD:
            out std_logic_vector(2 downto 0)
        );
    end component;

    component execute
        port(
        RegWriteInE, MemToRegInE, MemWriteInE, JumpInE, BranchInE, AluSrcE,
            RegDstE: in std_logic;
        AluControlE:
            in std_logic_vector(2 downto 0);
        RtE, RdE:
            in std_logic_vector(4 downto 0);
        RD1E, RD2E, PCPlus4E, SignImmE:
            in std_logic_vector(31 downto 0);

        RegWriteOutE, MemToRegOutE, MemWriteOutE, JumpOutE, BranchOutE, ZeroE:
            out std_logic;
        WriteRegE:
            out std_logic_vector(4 downto 0);
        AluResE, WriteDataE, PCBranchE:
            out std_logic_vector(31 downto 0)
        );
    end component;

    component memory
        port(
        RegWriteInM, MemToRegInM, JumpInM, MemWriteM, BranchM, ZeroM, clk, dump:
            in std_logic;
        WriteRegInM:
            in std_logic_vector(4 downto 0);
        AluResInM, WriteDataM, PCBranchInM:
            in std_logic_vector(31 downto 0);

        RegWriteOutM, MemToRegOutM, JumpOutM, PCSrcM:
            out std_logic;
        WriteRegOutM:
            out std_logic_vector(4 downto 0);
        AluResOutM, ReadDataM, PCBranchOutM:
            out std_logic_vector(31 downto 0)
        );
    end component;

    component writeback
        port(
        RegWriteInW, MemToRegW:
            in std_logic;
        WriteRegInW:
            in std_logic_vector(4 downto 0);
        AluOutW, ReadDataW:
            in std_logic_vector(31 downto 0);

        RegWriteOutW:
            out std_logic;
        WriteRegOutW:
            out std_logic_vector(4 downto 0);
        ResultW:
            out std_logic_vector(31 downto 0)
        );
    end component;

    component flopr
        generic(n: integer);
        port(
        d : in std_logic_vector(n downto 0);
        clk, rst: in std_logic;
        q: out std_logic_vector(n downto 0)
        );
    end component;

    constant IF_ID_SIZE: natural := 63;
    constant ID_EX_SIZE: natural := 147;
    constant EX_MEM_SIZE: natural := 106;
    constant MEM_WB_SIZE: natural := 70;

    -- Signals for pipeline registers
    signal IF_IDIn: std_logic_vector(IF_ID_SIZE downto 0);
    signal ID_EXIn: std_logic_vector(ID_EX_SIZE downto 0);
    signal EX_MEMIn: std_logic_vector(EX_MEM_SIZE downto 0);
    signal MEM_WBIn: std_logic_vector(MEM_WB_SIZE downto 0);

    signal IF_IDOut: std_logic_vector(IF_ID_SIZE downto 0);
    signal ID_EXOut: std_logic_vector(ID_EX_SIZE downto 0);
    signal EX_MEMOut: std_logic_vector(EX_MEM_SIZE downto 0);
    signal MEM_WBOut: std_logic_vector(MEM_WB_SIZE downto 0);

    -- no se si hace falta
    signal PCPlus4D: std_logic_vector(31 downto 0);

    -- Signals to Fetch
    signal JumpM_s, PCSrcM_s: std_logic;
    signal PCBranchM_s: std_logic_vector(31 downto 0);

    -- Signals to IF_ID
    signal InstrF_s, PCPlus4F_s: std_logic_vector(31 downto 0);

    -- Signals to Decode
    signal RegWriteOutW_s: std_logic;
    signal WriteRegOutW_s: std_logic_vector(4 downto 0);
    signal ResultW_s: std_logic_vector(31 downto 0);

    -- Signals to ID_EX
    signal MemToRegD_s, MemWriteD_s, BranchD_s, AluSrcD_s, RegDstD_s,
           RegWriteD_s, JumpD_s: std_logic;
    signal AluControlD_s: std_logic_vector(2 downto 0);
    signal RtD_s, RdD_s: std_logic_vector(4 downto 0);
    signal SigImmD_s, RD1D_s, RD2D_s, PCPlus4OutD_s: std_logic_vector(31 downto 0);

    -- Signals to EX_MEM
    signal RegWriteOutE_s, MemToRegOutE_s, MemWriteOutE_s, JumpOutE_s, 
           BranchOutE_s, ZeroE_s: std_logic;
    signal WriteRegE_s: std_logic_vector(4 downto 0);
    signal AluResE_s, WriteDataE_s, PCBranchE_s: std_logic_vector(31 downto 0);

    -- Signals to MEM_WB
    signal RegWriteOutM_s, MemToRegOutM_s: std_logic;
    signal WriteRegOutM_s: std_logic_vector(4 downto 0);
    signal AluResOutM_s, ReadDataM_s: std_logic_vector(31 downto 0);

begin
    Fetch_0: fetch
        port map(JumpM_s, PcSrcM_s, clk, rst, PcBranchM_s, InstrF_s, pc,
                 PCPlus4F_s);

    IF_IDIn <= InstrF_s & PCPlus4F_s;

    IF_ID: flopr
        generic map(IF_ID_SIZE)
        port map(IF_IDIn, clk, rst, IF_IDOut);

    Decode_0: decode
        port map(RegWriteOutW_s, clk, WriteRegOutW_s, IF_IDOut(63 downto 32),
                 ResultW_s, IF_IDOut(31 downto 0), RtD_s, RdD_s, SigImmD_s,
                 RD1D_s, RD2D_s, PCPlus4OutD_s, MemToRegD_s, MemWriteD_s,
                 BranchD_s, AluSrcD_s, RegDstD_s, RegWriteD_s, JumpD_s,
                 AluControlD_s);

    ID_EXIn <= RegWriteD_s & MemToRegD_s & MemWriteD_s & JumpD_s & BranchD_s
               & AluSrcD_s & RegDstD_s & AluControlD_s & RtD_s & RdD_s
               & RD1D_s & RD2D_s & PCPlus4OutD_s & SigImmD_s;

    ID_EX: flopr
        generic map(ID_EX_SIZE)
        port map(ID_EXIn, clk, rst, ID_EXOut);

    Exectute_0: execute
        port map(ID_EXOut(147), ID_EXOut(146), ID_EXOut(145), ID_EXOut(144),
                 ID_EXOut(143), ID_EXOut(142), ID_EXOut(141),
                 ID_EXOut(140 downto 138), ID_EXOut(137 downto 133),
                 ID_EXOut(132 downto 128), ID_EXOut(127 downto 96),
                 ID_EXOut(95 downto 64), ID_EXOut(63 downto 32),
                 ID_EXOut(31 downto 0), RegWriteOutE_s, MemToRegOutE_s,
                 MemWriteOutE_s, JumpOutE_s, BranchOutE_s, ZeroE_s, WriteRegE_s,
                 AluResE_s, WriteDataE_s, PCBranchE_s);

    EX_MEMIn <= RegWriteOutE_s & MemToRegOutE_s & JumpOutE_s & MemWriteOutE_s &
                BranchOutE_s & ZeroE_s & WriteRegE_s & AluResE_s & WriteDataE_s &
                PCBranchE_s;

    EX_MEM: flopr
        generic map(EX_MEM_SIZE)
        port map(EX_MEMIn, clk, rst, EX_MEMOut);

    Memory_0: memory
        port map(EX_MEMOut(106), EX_MEMOut(105), EX_MEMOut(104), EX_MEMOut(103),
                 EX_MEMOut(102), EX_MEMOut(101), clk, dump,
                 EX_MEMOut(100 downto 96), EX_MEMOut(95 downto 64),
                 EX_MEMOut(63 downto 32), EX_MEMOut(31 downto 0),
                 RegWriteOutM_s, MemToRegOutM_s, JumpM_s, PCSrcM_s, 
                 WriteRegOutM_s, AluResOutM_s, ReadDataM_s, PCBranchM_s);

    MEM_WBIn <= RegWriteOutM_s & MemToRegOutM_s & WriteRegOutM_s & AluResOutM_s
                & ReadDataM_s;

    MEM_WB: flopr
        generic map(MEM_WB_SIZE)
        port map(MEM_WBIn, clk, rst, MEM_WBOut);

    Writeback_0: writeback
        port map(MEM_WBOut(70), MEM_WBOut(69), MEM_WBOut(68 downto 64), 
                 MEM_WBOut(63 downto 32), MEM_WBOut(31 downto 0), 
                 RegWriteOutW_s, WriteRegOutW_s, ResultW_s);

    instr <= InstrF_s;
end behav;
